'''
    Created on May 15, 2010

    @author: Samuel Mendenhall (Samuel.Mendenhall@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''
from optparse import OptionParser
from subprocess import Popen, PIPE, STDOUT
from threading import Thread
import errno
import fileinput
import logging
import os
import os.path
import shutil
import stat
import subprocess
import sys
import time
import urllib
import urllib2
import zipfile

# TODO modify --start-jboss to --disable-start-jboss or something, the reverse would be better

# TODO make an option in the gui for ssl and --enable-ssl conditionally on that

# TODO update access.redhat.com links

# TODO add file:// to all logging 

# TODO look into curl/wget for automatically downloading files from the csp given a username/password
 # http://www.mail-archive.com/wget@sunsite.dk/msg07917.html
 # http://drupal.org/node/118759

# TODO replace os.system commans with tuple syntax

# TODO add EAP 5.1 beta

# TODO Add ability to specify Apache ServerName

# Add EWS as an option to install

# TODO Add -Djboss.cluster.jvmRoute=node1 instead of manually editing the server.xml (might only be for JBoss 5+)

# Test with Virtual Box + Ubuntu 32-bit

# Test with Virtual Box + KDE

# TODO add verbose to the cmd line args and set logging level

# TODO instead of if 1.0.3 and 1.1.0 make that a property in the map to specify if a 1.0.x release or 1.1.x release

# ** https://access.redhat.com/issue-tracker/1187273  contains info on installing EWS from zip
#  http://www.computerhope.com/unix/uxterm.htm
# http://www.linuxquestions.org/questions/linux-newbie-8/starting-bash-and-xterm-in-a-particular-directory-778287/

# To clarify...
"""The value for mod_cluster's advertise property can have 3 values: true,
false, or undefined.

When undefined, advertise will auto-enable if no proxyList was defined.

If the document to which Samuel refers is:
http://www.jboss.org/mod_cluster/java/properties.html

I think the confusion lies in the what is meant by a "default value".
The document uses "default" to mean the assumed value if none was
specified in the configuration file.  This is not to be confused with
the value specified in the default configuration file.  Since these
might be different depending on whether you're using the configuration
from the mod_cluster project distribution or the configuration shipped
with the AS.

The advertise property is configured in the *-jboss-beans.xml file
within mod_cluster.sar/META-INF.
The configuration shipped in the mod_cluster project distribution
defines advertise as true.
In the configuration shipped with the AS defines advertise as false, but
can be overridden via the jboss.mod_cluster.advertise.enabled system
property.

--http://www.jboss.org/mod_cluster/FAQ.html
"""
#


##################################################################################
# Run common operations and set global variables
##################################################################################

class ClusterConfig:
    
    def apacheThreadGroup(self):
        clusterConfig.buildApache()
        clusterConfig.configureApache()
        clusterConfig.buildLoadbalancer()
        clusterConfig.configureLoadbalancer()
        
    def jbossThreadGroup(self):
        clusterConfig.setupJBoss()
        clusterConfig.configureJBoss()
    
    def __init__(self, passedInOptions=None):
        localVersion = '.85'
                
        ##################################################################################
        # Parse the cmd line options
        ##################################################################################
        parser=OptionParser(usage="%prog see http://clusterconfig.appspot.com for easy argument generation for this program", version="%prog " + localVersion)
        parser.add_option("--jboss-type", dest="jbossType", help="Defines the type of JBoss, valid values: Enterprise or Community")
        parser.add_option("--jboss-version", dest="jbossVersion", help="The version of JBoss in use, ex. 4.2.0.GA_CP01, 5.0.1.  See the source code for jbossVersions for a full list")
        parser.add_option("--ip-addresses", dest="ipAddresses", help="For 1 instance use 127.0.0.1 for example, for 2 127.0.0.2, and so on")
        parser.add_option("--httpd-version", dest="httpdVersion", help="Apache httpd version ex. 2.2.14, 2.2.15")
        parser.add_option("--loadbalancer", dest="loadbalancer", help="Loadbalancing software, ie. mod_jk, mod_cluster, or mod_proxy")
        parser.add_option("--modjk-version", dest="modjkVersion", help="mod_jk version, ex. 1.2.28, 1.2.29, 1.2.30")
        parser.add_option("--jboss-instances", dest="jbossInstances", default=1, help="Number of JBoss instances, default 1")
        parser.add_option("--modcluster-version", dest="modClusterVersion", help="Version of mod_cluster to use with Apache, ex. 1.1.0.CR2, use the format as generated at http://clusterconfig.appspot.com")
        parser.add_option("--modcluster-advertise", dest="modClusterAdvertise", default="true", help="true for multicast (Default), false for a defined proxyList")
        parser.add_option("--start-jboss", dest="startJBoss", default="true", help="true to automatically spawn JBoss on completion (Default)  Set to false mainly for testing purposes")
        parser.add_option("--architecture", dest="architecture", help="OS Architecture, ie x86_64 or 32 bit, ex. rhel5_64, rhel5_32, other_linux_64, other_linux_32")
        parser.add_option("--sandbox-dir-name", dest="sandboxDirectoryName", help="Sandbox directory were all compilation and work is done.  Typically this is not needed to be modified, unless running test.py, as it defaults to the current directory + '/sandbox'. ")
        parser.add_option("--archives-dir", dest="dirArchives", default=None, help="Archives directory were all downloaded files are stored for repeat use.  Typically this is not needed to be modified as it defaults to the current directory + '/archives'. If you have an existing directory that contains all of your JBoss/Apache/ect... zips you can set this option to that directory path")
        #--jboss-version 5.0.1 --jboss-type Enterprise --jboss-instances 1 --ip-addresses 127.0.0.1 --httpd-version 2.2.15 --loadbalancer mod_cluster --architecture rhel5_64 --modcluster-advertise false
        #['--jboss-version', '5.0.1', '--jboss-type', 'Enterprise', '--jboss-instances', '1', '--ip-addresses', '127.0.0.1', '--httpd-version', '2.2.15' + '--loadbalancer', 'mod_cluster', '--architecture', 'rhel5_64', '--modcluster-advertise', 'false']
        if passedInOptions == None:
            (cmdLineOptions, args) = parser.parse_args()
        else:
            (cmdLineOptions, args) = parser.parse_args(passedInOptions)
            
        ##################################################################################
        # Configure logging
        ##################################################################################    
        logging.basicConfig(level=logging.DEBUG)
        self.log = logging.getLogger(name="clusterconfig")

        #print("options:", str(cmdLineOptions))
        #print("arguments:", args)
        #print type(cmdLineOptions)
        
        self.options = cmdLineOptions
        
        
        ##################################################################################
        # Verifying necessary information to determine whether clusterconfig can 
        # successfully run
        ##################################################################################
        Utility.prettyPrint("Verifying the latest version of clusterconfig.py is in use")
        latestVersion = Utility.getWebpageContent('http://clusterconfig.appspot.com/version.txt')
        self.log.info('Latest version of cluster config is %s local version %s', latestVersion, localVersion)
        if(localVersion != latestVersion):
            self.log.warn('Please upgrade to the latest version, you can download the latest version with the following command> wget http://clusterconfig.appspot.com/clusterconfig.py')
            self.log.warn('Optionally you can edit this python script and comment out the sys.exit(1) below this log line.')
            sys.exit(1)
            
        #gcc and java are required for building Apache and running JBoss, exit if these don't exist.    
        Utility.doesBinaryExist("gcc", True, False)
        Utility.doesBinaryExist("java", True, False)
        
        #Now check if there is gnome-terminal, if not check xterm, warn but not fail, just 
        #won't be able to open terminals
        Utility.doesBinaryExist("gnome-terminal", False, True)
        Utility.doesBinaryExist("xterm", False, True)
        
        
        ##################################################################################
        # Performing other necessary setup routines
        ##################################################################################
        
        #Remove white spaces from ipAddresses, if not, things can go haywire
        self.options.ipAddresses = self.options.ipAddresses.replace(' ','')
        
        #make the modClusterAdvertise lowercase incase the user inputs True or False instead of true or false.  Yes there is a better way to do this, submit a patch if you want
        self.options.modClusterAdvertise = self.options.modClusterAdvertise.lower()
        
        #Every execution of clusterconfig will at least have a jbossVersion specified, so check the options for this
        if self.options.jbossVersion == None:
            self.log.error("Options not correctly specified")
            return
        
        self.dirCurrent = os.path.realpath(os.curdir)
        self.log.debug("Current Directory set to %s", self.dirCurrent)
        
        if self.options.dirArchives == None:
            self.dirArchives = self.dirCurrent + "/archives"
        else:
            self.dirArchives = self.options.dirArchives
        
        if not os.path.isdir(self.dirArchives):
            self.log.debug("Attempting to create directory %s", self.dirArchives)
            os.mkdir(self.dirArchives, 0777)
            self.log.debug("Archives directory (where all files are downloaded and stored) is set to " + self.dirArchives)
        archiveSubDirs = ["apache", "jboss", "mod_cluster", "mod_jk", "ews"]
        for subDir in archiveSubDirs:
            if not os.path.isdir(self.dirArchives + "/" + subDir):
                self.log.debug("Attempting to create directory %s", self.dirArchives + "/" + subDir)
                os.mkdir(self.dirArchives + "/" + subDir, 0777)
                self.log.debug("created subdirectory %s in the archives directory", subDir)
            
        self.httpdMirror="http://archive.apache.org/dist/httpd"
        
        self.necessaryModClusterSoFilenames = ("mod_proxy.so", "mod_proxy_ajp.so", "mod_slotmem.so", "mod_manager.so", "mod_proxy_cluster.so", "mod_advertise.so ")
        
        #Brute force, but have to list out all of the versions and locations of downloads for each mod_cluster and JBoss version so I can look it up later more cleanly
        self.modClusterSoVersions = {
            "Enterprise_5.0.1_rhel5_64" : ModClusterInformation("jboss-eap-native-5.0.1-RHEL5-x86_64.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=2303", "jboss-eap-5.0"),
            "Enterprise_5.0.1_rhel5_32" : ModClusterInformation("jboss-eap-native-5.0.1-RHEL5-i386.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=2293", "jboss-eap-5.0"),
            "Enterprise_5.0.1_rhel4_64" : ModClusterInformation("jboss-eap-native-5.0.1-RHEL4-x86_64.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=2283", "jboss-eap-5.0"),
            "Enterprise_5.0.1_rhel4_32" : ModClusterInformation("jboss-eap-native-5.0.1-RHEL4-x86_64.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=2273", "jboss-eap-5.0"),
            
            "Enterprise_5.0.0_rhel5_64" : ModClusterInformation("jboss-eap-native-5.0.0_mod-cluster-RHEL5-x86_64.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=1293", "jboss-eap-5.0"),
            "Enterprise_5.0.0_rhel5_32" : ModClusterInformation("jboss-eap-native-5.0.0_mod-cluster-RHEL5-i386.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=1283", "jboss-eap-5.0"),
            "Enterprise_5.0.0_rhel4_64" : ModClusterInformation("jboss-eap-native-5.0.0_mod-cluster-RHEL4-x86_64.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=1273", "jboss-eap-5.0"),
            
            "Enterprise_5.1.0.Beta_rhel5_64" : ModClusterInformation("jboss-ep-native-5.1.0.Beta-RHEL5-x86_64.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=3543", "jboss-eap-5.1"),
            "Enterprise_5.1.0.Beta_rhel5_32" : ModClusterInformation("jboss-ep-native-5.1.0.Beta-RHEL5-i386.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=3533", "jboss-eap-5.1"),
            "Enterprise_5.1.0.Beta_rhel4_64" : ModClusterInformation("jboss-ep-native-5.1.0.Beta-RHEL4-x86_64.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=3523", "jboss-eap-5.1"),
            "Enterprise_5.1.0.Beta_rhel4_32" : ModClusterInformation("jboss-ep-native-5.1.0.Beta-RHEL4-i386.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=3513", "jboss-eap-5.1"),
            
            "Enterprise_5.1.0_rhel5_64" : ModClusterInformation("jboss-ep-native-5.1.0-RHEL5-x86_64.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=4133", "jboss-ep-5.1"),
            "Enterprise_5.1.0_rhel5_32" : ModClusterInformation("jboss-ep-native-5.1.0-RHEL5-i386.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=4123", "jboss-ep-5.1"),
            "Enterprise_5.1.0_rhel4_64" : ModClusterInformation("jboss-ep-native-5.1.0-RHEL4-x86_64.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=4113", "jboss-ep-5.1"),
            "Enterprise_5.1.0_rhel4_32" : ModClusterInformation("jboss-ep-native-5.1.0-RHEL4-i386.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=4103", "jboss-ep-5.1"),
            
            "Community_1.0.3.GA_rhel5_64" : ModClusterInformation("mod_cluster-1.0.3.GA-linux2-x64-so.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.3.GA/mod_cluster-1.0.3.GA-linux2-x64-so.tar.gz", ""),
            "Community_1.0.3.GA_rhel4_64" : ModClusterInformation("mod_cluster-1.0.3.GA-linux2-x64-so.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.3.GA/mod_cluster-1.0.3.GA-linux2-x64-so.tar.gz", ""),
            "Community_1.0.3.GA_other_linux_64" : ModClusterInformation("mod_cluster-1.0.3.GA-linux2-x64-so.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.3.GA/mod_cluster-1.0.3.GA-linux2-x64-so.tar.gz", ""),
            "Community_1.0.3.GA_rhel5_32" : ModClusterInformation("mod_cluster-1.0.3.GA-linux2-x86-so.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.3.GA/mod_cluster-1.0.3.GA-linux2-x86-so.tar.gz", ""),
            "Community_1.0.3.GA_rhel4_32" : ModClusterInformation("mod_cluster-1.0.3.GA-linux2-x86-so.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.3.GA/mod_cluster-1.0.3.GA-linux2-x86-so.tar.gz", ""),
            "Community_1.0.3.GA_other_linux_32" : ModClusterInformation("mod_cluster-1.0.3.GA-linux2-x86-so.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.3.GA/mod_cluster-1.0.3.GA-linux2-x86-so.tar.gz", ""),
            
            "Community_1.0.4.GA_rhel5_64" : ModClusterInformation("mod_cluster-1.0.4.GA-linux2-x64-ssl.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.4.GA/mod_cluster-1.0.4.GA-linux2-x64-ssl.tar.gz", ""),
            "Community_1.0.4.GA_rhel4_64" : ModClusterInformation("mod_cluster-1.0.4.GA-linux2-x64-ssl.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.4.GA/mod_cluster-1.0.4.GA-linux2-x64-ssl.tar.gz", ""),
            "Community_1.0.4.GA_other_linux_64" : ModClusterInformation("mod_cluster-1.0.4.GA-linux2-x64-ssl.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.4.GA/mod_cluster-1.0.4.GA-linux2-x64-ssl.tar.gz", ""),
            "Community_1.0.4.GA_rhel5_32" : ModClusterInformation("mod_cluster-1.0.4.GA-linux2-x86-ssl.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.4.GA/mod_cluster-1.0.4.GA-linux2-x86-ssl.tar.gz", ""),
            "Community_1.0.4.GA_rhel4_32" : ModClusterInformation("mod_cluster-1.0.4.GA-linux2-x86-ssl.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.4.GA/mod_cluster-1.0.4.GA-linux2-x86-ssl.tar.gz", ""),
            "Community_1.0.4.GA_other_linux_32" : ModClusterInformation("mod_cluster-1.0.4.GA-linux2-x86-ssl.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.4.GA/mod_cluster-1.0.4.GA-linux2-x86-ssl.tar.gz", ""),
            
            "Community_1.1.0.CR2_rhel5_64" : ModClusterInformation("mod_cluster-1.1.0.CR2-linux2-x64-ssl.tar.gz", "http://downloads.jboss.org/mod_cluster/1.1.0.CR2/mod_cluster-1.1.0.CR2-linux2-x64-ssl.tar.gz", ""),
            "Community_1.1.0.CR2_rhel4_64" : ModClusterInformation("mod_cluster-1.1.0.CR2-linux2-x64-ssl.tar.gz", "http://downloads.jboss.org/mod_cluster/1.1.0.CR2/mod_cluster-1.1.0.CR2-linux2-x64-ssl.tar.gz", ""),
            "Community_1.1.0.CR2GA_other_linux_64" : ModClusterInformation("mod_cluster-1.1.0.CR2-linux2-x64-ssl.tar.gz", "http://downloads.jboss.org/mod_cluster/1.1.0.CR2/mod_cluster-1.1.0.CR2-linux2-x64-ssl.tar.gz", ""),
            "Community_1.1.0.CR2_rhel5_32" : ModClusterInformation("mod_cluster-1.1.0.CR2-linux2-x86-so.tar.gz", "http://downloads.jboss.org/mod_cluster/1.1.0.CR2/mod_cluster-1.1.0.CR2-linux2-x86-so.tar.gz", ""),
            "Community_1.1.0.CR2_rhel4_32" : ModClusterInformation("mod_cluster-1.1.0.CR2-linux2-x86-so.tar.gz", "http://downloads.jboss.org/mod_cluster/1.1.0.CR2/mod_cluster-1.1.0.CR2-linux2-x86-so.tar.gz", ""),
            "Community_1.1.0.CR2_other_linux_32" : ModClusterInformation("mod_cluster-1.1.0.CR2-linux2-x86-so.tar.gz", "http://downloads.jboss.org/mod_cluster/1.1.0.CR2/mod_cluster-1.1.0.CR2-linux2-x86-so.tar.gz", "")
        }
        
        self.modClusterSarVersions = {
            "Community_1.0.3.GA" : ModClusterInformation("mod-cluster-1.0.3.GA-bin.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.3.GA/mod-cluster-1.0.3.GA-bin.tar.gz", ""),
            "Community_1.0.4.GA" : ModClusterInformation("mod-cluster-1.0.4.GA-bin.tar.gz", "http://downloads.jboss.org/mod_cluster/1.0.4.GA/mod-cluster-1.0.4.GA-bin.tar.gz", ""),
            "Community_1.1.0.CR3" : ModClusterInformation("mod_cluster-1.1.0.CR3-bin.tar.gz", "http://downloads.jboss.org/mod_cluster/1.1.0.CR3/mod_cluster-1.1.0.CR3-bin.tar.gz", "")
        }
        
        self.jbossVersions = {
            "4.2.0.GA": JBossInformation("4.2.0.GA", "jboss-eap-4.2.0-1.ep1.1.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=423", "jboss-eap-4.2", "Enterprise"),
            "4.2.0.GA_CP01": JBossInformation("4.2.0.GA_CP01", "jboss-eap-4.2.0-2.CP01.ep1.3.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=452", "jboss-eap-4.2", "Enterprise"),
            "4.2.0.GA_CP02": JBossInformation("4.2.0.GA_CP02", "jboss-eap-4.2.0-2.CP01.ep1.3.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=515", "jboss-eap-4.2", "Enterprise"),
            "4.2.0.GA_CP03": JBossInformation("4.2.0.GA_CP03", "jboss-eap-4.2.0.GA_CP03.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=569", "jboss-eap-4.2", "Enterprise"),
            "4.2.0.GA_CP04": JBossInformation("4.2.0.GA_CP04", "jboss-eap-4.2.0.GA_CP04.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=630", "jboss-eap-4.2", "Enterprise"),
            "4.2.0.GA_CP05": JBossInformation("4.2.0.GA_CP05", "jboss-eap-4.2.0.GA_CP05.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=700", "jboss-eap-4.2", "Enterprise"),
            "4.2.0.GA_CP06": JBossInformation("4.2.0.GA_CP06", "jboss-eap-4.2.0.GA_CP06.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=784", "jboss-eap-4.2", "Enterprise"),
            "4.2.0.GA_CP07": JBossInformation("4.2.0.GA_CP07", "jboss-eap-4.2.0.GA_CP07.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=903", "jboss-eap-4.2", "Enterprise"),
            "4.2.0.GA_CP08": JBossInformation("4.2.0.GA_CP08", "jboss-eap-4.2.0.GA_CP08.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=1042", "jboss-eap-4.2", "Enterprise"),
            "4.2.0.GA_CP09": JBossInformation("4.2.0.GA_CP09", "jboss-eap-4.2.0.GA_CP09.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=2403", "jboss-eap-4.2", "Enterprise"),
            "4.3.0.GA": JBossInformation("4.3.0.GA", "jboss-eap-4.3.0.GA-1.ep1.8.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=477", "jboss-eap-4.3", "Enterprise"),
            "4.3.0.GA_CP01": JBossInformation("4.3.0.GA_CP01", "jboss-eap-4.3.0.GA_CP01.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=570", "jboss-eap-4.3", "Enterprise"),
            "4.3.0.GA_CP02": JBossInformation("4.3.0.GA_CP02", "jboss-eap-4.3.0.GA_CP02.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=634", "jboss-eap-4.3", "Enterprise"),
            "4.3.0.GA_CP03": JBossInformation("4.3.0.GA_CP03", "jboss-eap-4.3.0.GA_CP03.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=704", "jboss-eap-4.3", "Enterprise"),
            "4.3.0.GA_CP04": JBossInformation("4.3.0.GA_CP04", "jboss-eap-4.3.0.GA_CP04.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=780", "jboss-eap-4.3", "Enterprise"),
            "4.3.0.GA_CP05": JBossInformation("4.3.0.GA_CP05", "jboss-eap-4.3.0.GA_CP05.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=907", "jboss-eap-4.3", "Enterprise"),
            "4.3.0.GA_CP06": JBossInformation("4.3.0.GA_CP06", "jboss-eap-4.3.0.GA_CP06.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=925", "jboss-eap-4.3", "Enterprise"),
            "4.3.0.GA_CP07": JBossInformation("4.3.0.GA_CP07", "jboss-eap-4.3.0.GA_CP07.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=1046", "jboss-eap-4.3", "Enterprise"),
            "4.3.0.GA_CP08": JBossInformation("4.3.0.GA_CP08", "jboss-eap-4.3.0.GA_CP08.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=2453", "jboss-eap-4.3", "Enterprise"),
            "5.0.0": JBossInformation("5.0.0", "jboss-eap-5.0.0.GA.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=1014", "jboss-eap-5.0", "Enterprise"),
            "5.0.1": JBossInformation("5.0.1", "jboss-eap-5.0.1.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=2233", "jboss-eap-5.0", "Enterprise"),
            "5.1.0.Beta": JBossInformation("5.1.0.Beta", "jboss-eap-5.1.0.Beta.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=3473", "jboss-eap-5.1", "Enterprise"),
            "5.1.0": JBossInformation("5.1.0", "jboss-eap-5.1.0.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=4063", "jboss-eap-5.1", "Enterprise"),
            
            "4.0.5.GA": JBossInformation("4.0.5.GA", "jboss-4.0.5.GA.zip", "http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-4.0.5.GA/jboss-4.0.5.GA.zip?use_mirror=iweb", "jboss-4.0.5.GA", "Community"),
            "4.2.2.GA": JBossInformation("4.2.2.GA", "jboss-4.2.2.GA.zip", "http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-4.2.2.GA/jboss-4.2.2.GA.zip?use_mirror=iweb", "jboss-4.2.2.GA", "Community"),
            "4.2.3.GA": JBossInformation("4.2.3.GA", "jboss-4.2.3.GA.zip", "http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-4.2.3.GA/jboss-4.2.3.GA.zip?use_mirror=voxel", "jboss-4.2.3.GA", "Community"),
            "5.0.0.GA": JBossInformation("5.0.0.GA", "jboss-5.0.0.GA.zip", "http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-5.0.0.GA/jboss-5.0.0.GA.zip?use_mirror=iweb", "jboss-5.0.0.GA", "Community"),
            "5.0.1.GA": JBossInformation("5.0.1.GA", "jboss-5.0.1.GA.zip", "http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-5.0.1.GA/jboss-5.0.1.GA.zip?use_mirror=iweb", "jboss-5.0.1.GA", "Community"),
            "5.1.0.GA": JBossInformation("5.1.0.GA", "jboss-5.1.0.GA.zip", "http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-5.1.0.GA/jboss-5.1.0.GA.zip?use_mirror=iweb", "jboss-5.1.0.GA", "Community"),
            "6.0.0-M3" : JBossInformation("5.1.0.GA", "jboss-as-distribution-6.0.0.20100429-M3.zip", "http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-6.0.0.M3/jboss-as-distribution-6.0.0.20100429-M3.zip?use_mirror=superb-sea2", "jboss-6.0.0.20100429-M3", "Community")
            }
        
        self.ipAddresses = self.options.ipAddresses.split(',')
        
        #Test if the self.ipAddresses match up to the ips specified, it can be easy to put a whitespace in here and mess script up later when generating the jboss run scripts
        sanitizedIpAddresses = []
        for ipAddress in self.ipAddresses:
            if len(ipAddress) >= 9:
                sanitizedIpAddresses.append(ipAddress)
                
        print sanitizedIpAddresses
        
        if len(sanitizedIpAddresses) != int(self.options.jbossInstances):
            sys.exit("JBoss instances set to " + str(self.options.jbossInstances) + " but only " + str(len(sanitizedIpAddresses)) + " IP Addresses specified, " + str(sanitizedIpAddresses) + ", probably a typo or extraneous whitespace")
            
        #Make sure necessary Enterprise Products are downloaded
        #TODO, why am I doing this here?
        if self.options.jbossType == "Enterprise":
            Utility.downloadEnterpriseProductIfNotInArchives(self.jbossVersions[self.options.jbossVersion].filename, self.jbossVersions[self.options.jbossVersion].url, self.dirArchives + "/jboss")
            modClusterKey = self.options.jbossType + "_" + self.options.jbossVersion + "_" + self.options.architecture
            #Only download mod_cluster if it is selected
            if self.options.modClusterVersion != None:
                Utility.downloadEnterpriseProductIfNotInArchives(self.modClusterSoVersions[modClusterKey].filename, self.modClusterSoVersions[modClusterKey].url, self.dirArchives + "/jboss")
                if "5.0.0" in self.options.jbossVersion:
                    Utility.downloadEnterpriseProductIfNotInArchives("jboss-eap-native-5.0.0_mod-cluster-bin.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=1243", self.dirArchives + "/jboss")
                
        
        #Setup necessary directories sandbox and sandbox/temp
        self.log.debug("sandboxDirectoryName %s", self.options.sandboxDirectoryName)
        if self.options.sandboxDirectoryName == None:
            self.dirSandbox = self.dirCurrent + "/" + "sandbox"
        else:
            self.dirSandbox = self.dirCurrent + "/" + self.options.sandboxDirectoryName
        self.dirSandboxTemp = self.dirSandbox + "/temp"
        
        if os.path.isdir(self.dirSandbox):
            shutil.rmtree(self.dirSandbox, ignore_errors=False, onerror=Utility.handleRemoveReadonly)
        self.log.info("Attempting to create directory: " + self.dirSandbox)
        os.mkdir(self.dirSandbox)
            
        if not os.path.isdir(self.dirSandboxTemp):
            self.log.info("Attempting to create directory: " + self.dirSandboxTemp)
            os.mkdir(self.dirSandboxTemp)
            
        #Set the Apache install directory 
        self.dirApacheInstall = self.dirSandbox + "/apache"
        
    ##################################################################################
    # Setup JBoss
    ##################################################################################
    def setupJBoss(self):
        Utility.prettyPrint("Setting up JBoss")
        
        if self.options.jbossType == "Enterprise":
            Utility.downloadEnterpriseProductIfNotInArchives(self.jbossVersions[self.options.jbossVersion].filename, self.jbossVersions[self.options.jbossVersion].url, self.dirArchives + "/jboss")
        else:
            Utility.downloadIfNotInArchives(self.jbossVersions[self.options.jbossVersion].filename, self.jbossVersions[self.options.jbossVersion].url, self.dirArchives + "/jboss")
        
        jbossToUnzip = self.dirArchives + "/jboss/" + self.jbossVersions[self.options.jbossVersion].filename
        self.log.info(jbossToUnzip)
        Utility.unzipFileIntoDirOnLinux(jbossToUnzip, self.dirSandbox)
        
        #The eap doesn't extract as the filename, so take that into account
        self.jbossHome = self.dirSandbox + "/" + self.jbossVersions[self.options.jbossVersion].extractsAs
    
        #The eap also adds a jboss-as directory, and that is the real JBOSS_HOME
        if "Enterprise" == self.options.jbossType:
            self.jbossHome = self.jbossHome + "/jboss-as"
            
        #Make all run.sh executable
        Utility.makeFileExecutable(self.jbossHome + "/bin/run.sh")
    
        self.log.info("jbossHome set to " + self.jbossHome)
        
    ##################################################################################
    # Configure JBoss
    ##################################################################################
    def configureJBoss(self):
        Utility.prettyPrint("Configuring JBoss")
        
        for i in range(int(self.options.jbossInstances)):
            #Copy the JBOSS_HOME/server/all to each node
            nodeName = "node" + str(i+1)
            Utility.copyDirsOnLinux(self.jbossHome + "/server/all", self.jbossHome + "/server/" + nodeName)
            
            #Copy the counter.war to the appropriate node
            Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/counter.war",  self.dirSandboxTemp + "/counter.war")
            Utility.moveOnLinux(self.dirSandboxTemp + "/counter.war", self.jbossHome + "/server/" + nodeName + "/deploy")
            
            #Add admin=admin to the jmx props
            Utility.appendToFile(self.jbossHome + "/server/" + nodeName + "/conf/props/jmx-console-users.properties", "admin=admin")
            
            #Configure the EAP/Community 4.3/5
            if "4.0" in self.options.jbossVersion:
                Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/eap/40/server.xml", self.dirSandboxTemp + "/server.xml")
                Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/eap/40/jboss-service.xml", self.dirSandboxTemp + "/jboss-service.xml")
                #Replace necessary values
                Utility.replaceStringInFile(self.dirSandboxTemp + "/server.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb-tomcat55.sar/server.xml", "jvmRoute=\"\"", "jvmRoute=\"" + nodeName + "\"")
                Utility.moveOnLinux(self.dirSandboxTemp + "/jboss-service.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb-tomcat55.sar/META-INF/jboss-service.xml")
            elif "4." in self.options.jbossVersion:
                Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/eap/43/server.xml", self.dirSandboxTemp + "/server.xml")
                Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/eap/43/jboss-service.xml", self.dirSandboxTemp + "/jboss-service.xml")
                #Replace necessary values
                Utility.replaceStringInFile(self.dirSandboxTemp + "/server.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jboss-web.deployer/server.xml", "jvmRoute=\"\"", "jvmRoute=\"" + nodeName + "\"")
                Utility.moveOnLinux(self.dirSandboxTemp + "/jboss-service.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jboss-web.deployer/META-INF/jboss-service.xml")
            elif "5." in self.options.jbossVersion:
                #If this is mod_cluster we are going to modify this anyway, so unecessary to do here.
                if not self.options.loadbalancer == 'mod_cluster':
                    Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/eap/500/server.xml", self.dirSandboxTemp + "/server.xml")
                    #Replace necessary values
                    Utility.replaceStringInFile(self.dirSandboxTemp + "/server.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/server.xml", "jvmRoute=\"\"", "jvmRoute=\"" + nodeName + "\"")
                
            #Create the run scripts for JBoss
            startJBossScript = self.jbossHome + "/bin/run.sh -c " + nodeName + " -b " + self.ipAddresses[i] + " -Djboss.messaging.ServerPeerID=" + str(i)
            stopJBossScript = self.jbossHome + "/bin/shutdown.sh -s jnp://" + self.ipAddresses[i] + ":1099 -S -u admin -p admin" 
            if self.options.modClusterAdvertise == "false":
                #HARDCODED the Apache address
                startJBossScript += " -Djboss.modcluster.proxyList=127.0.0.1:6666"
            Utility.writeToFile(self.dirSandbox + "/" + nodeName + "-start-jboss.sh", startJBossScript)
            Utility.writeToFile(self.dirSandbox + "/" + nodeName + "-stop-jboss.sh", stopJBossScript)
            Utility.makeFileExecutable(self.dirSandbox + "/" + nodeName + "-start-jboss.sh")
            Utility.makeFileExecutable(self.dirSandbox + "/" + nodeName + "-stop-jboss.sh")
    #        echo -e "$JBOSS_HOME/bin/run.sh -c $NODE_NAME -b ${IP_ADDRESSES_ARRAY[i-1]}" > $DIR_SANDBOX/jboss-${NODE_NAME}.sh
            #chmod +x $DIR_SANDBOX/jboss-${NODE_NAME}.sh
        
    ##################################################################################
    # Build Apache
    ##################################################################################
    def buildApache(self):
        Utility.prettyPrint("Building Apache")
        
        httpdVersionFile = "httpd-" + self.options.httpdVersion + ".tar.gz"
        
        Utility.downloadIfNotInArchives(httpdVersionFile, self.httpdMirror + "/" + httpdVersionFile, self.dirArchives + "/apache")
        
        self.log.info("Extracting %s to %s", self.dirArchives + "/apache/" + httpdVersionFile, self.dirSandboxTemp)
        os.chdir(self.dirSandboxTemp)
        Utility.extractTargzIntoDirOnLinux(self.dirArchives + "/apache/" + httpdVersionFile, self.dirSandboxTemp)
        self.log.info("Building Apache httpd to %s", self.dirApacheInstall)
        os.chdir(self.dirSandboxTemp + "/httpd-" + self.options.httpdVersion)
        if self.options.loadbalancer == "mod_cluster":
            os.system("./configure -q --prefix=" + self.dirApacheInstall + " --enable-ssl --with-mpm=worker --enable-proxy --enable-proxy-http --enable-proxy-ajp --disable-proxy-balancer --enable-rewrite")
        elif self.options.loadbalancer == "mod_proxy":
            os.system("./configure -q --prefix=" + self.dirApacheInstall + " --enable-ssl --with-mpm=worker --enable-proxy --enable-proxy-http --enable-proxy-ajp --enable-rewrite")
        elif self.options.loadbalancer == 'mod_jk':
            os.system("./configure -q --prefix=" + self.dirApacheInstall + " --with-mpm=worker --enable-rewrite")
        os.system("make --quiet --silent")
        os.system("make --quiet --silent install")
        self.log.info("Done building Apache")
    
    ##################################################################################
    # Build Apache
    ##################################################################################
    def configureApache(self):
        Utility.prettyPrint("Configuring Apache")
        
        serverStatus = """
    ExtendedStatus On
    <Location /server-status>
        SetHandler server-status
        Order Deny,Allow
        Deny from all
        Allow from 127.0.0.1
    </Location>
        """
        Utility.appendToFile(self.dirApacheInstall + "/conf/httpd.conf", serverStatus)
        
        #This could be probably reduced down to just one method which replaces the ServerName
        #Change #ServerName www.example.com:80 to Servername localhost:80
        self.log.info("Copying %s to %s", self.dirApacheInstall + "/conf/httpd.conf", self.dirApacheInstall + "/conf/httpd.conf.tmp")
        shutil.copy2(self.dirApacheInstall + "/conf/httpd.conf", self.dirApacheInstall + "/conf/httpd.conf.tmp")
        os.system("sed -e 's/#ServerName/ServerName/' -e 's/www\.example.com:80/localhost:80/' " + self.dirApacheInstall + "/conf/httpd.conf.tmp > " + self.dirApacheInstall + "/conf/httpd.conf")
        os.system("rm " + self.dirApacheInstall + "/conf/httpd.conf.tmp")
        
        #Change the LogLevel to debug for Apache
        Utility.appendToFile(self.dirApacheInstall + "/conf/httpd.conf", "\nLogLevel debug\n")
        
        #Change the LogLevel to debug for mod_rewrite
        Utility.appendToFile(self.dirApacheInstall + "/conf/httpd.conf", "\nRewriteLog \"logs/rewrite.log\"")
        Utility.appendToFile(self.dirApacheInstall + "/conf/httpd.conf", "\nRewriteLogLevel 10")
        
        #Add a health check html page to the base htdocs to test if apache is up
        Utility.writeToFile(self.dirApacheInstall + "/htdocs/health.html", "Apache is up!")
        
        #create run scripts for apache
        Utility.writeToFile(self.dirSandbox + "/apache.sh", "sudo " + self.dirApacheInstall + "/bin/apachectl $1")
        Utility.makeFileExecutable(self.dirSandbox + "/apache.sh")
       
    ##################################################################################
    # Build the Loadbalancer, either mod_jk, mod_cluster, or mod_proxy
    ##################################################################################
    def buildLoadbalancer(self):
        if self.options.loadbalancer == 'mod_jk':
            Utility.prettyPrint("Building " + self.options.loadbalancer)
            
            modjkMirror = "http://archive.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-" + self.options.modjkVersion
            modjkVersionFilename = "tomcat-connectors-" + self.options.modjkVersion + "-src.tar.gz"
            os.chdir(self.dirSandboxTemp)
            Utility.downloadIfNotInArchives(modjkVersionFilename, modjkMirror + "/" + modjkVersionFilename, self.dirArchives + "/mod_jk")
            Utility.extractTargzIntoDirOnLinux(Utility.archiveLocation(self.dirArchives + "/mod_jk", modjkVersionFilename), self.dirSandboxTemp)
            self.log.info("Building mod_jk against %s", self.dirApacheInstall)
            os.chdir(self.dirSandboxTemp + "/tomcat-connectors-" + self.options.modjkVersion + "-src/native")
            os.system("./configure --with-apxs=" + self.dirApacheInstall + "/bin/apxs")
            os.system("make --quiet --silent")
            os.system("make --quiet --silent install")
            self.log.info("Done building mod_jk")
    
        
    def configureLoadbalancer(self):
        Utility.prettyPrint("Configuring " + self.options.loadbalancer)
        
        ###############################################################
        # mod_jk
        ###############################################################
        if self.options.loadbalancer == 'mod_jk':
            Utility.appendToFile(self.dirApacheInstall + "/conf/httpd.conf", "\n# Include mod_jk configuration file\nInclude conf/mod-jk.conf")
            
            #get mod-jk.conf and output to the conf dir in Apache
            #Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/mod-jk.conf", self.dirApacheInstall + "/conf/mod-jk.conf")
            modJkDotConf = """
LoadModule jk_module modules/mod_jk.so
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel debug
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"

# For mod_rewrite compatibility, use +ForwardURIProxy (default since 1.2.24)
JkOptions +ForwardKeySize +ForwardURICompatUnparsed -ForwardDirectories

JkRequestLogFormat "%w %V %T"

JkMountFile conf/uriworkermap.properties

JkShmFile run/jk.shm

<Location /jkstatus>
    JkMount status
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
</Location>
"""            
            Utility.writeToFile(self.dirApacheInstall + "/conf/mod-jk.conf", modJkDotConf)
            
            #get uriworkermap.properties and output to the conf dir in Apache
            #Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/uriworkermap.properties", self.dirApacheInstall + "/conf/uriworkermap.properties")
            uriWorkmapDotProperties = """
/*=loadbalancer
!/health.html=loadbalancer
"""            
            Utility.writeToFile(self.dirApacheInstall + "/conf/uriworkermap.properties", uriWorkmapDotProperties)
            
            #generate the workermap.properties based on the number of JBoss instances
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.list=loadbalancer,status\n")
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.template.port=8009\n")
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.template.type=ajp13\n")
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.template.ping_mode=A\n")
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.template.socket_timeout=10\n")
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.template.connection_pool_size=10\n")
            workers = ""
            for i in range(int(self.options.jbossInstances)):
                Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.node" + str(i+1) + ".reference=worker.template\n")
                Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.node" + str(i+1) + ".host=" + self.ipAddresses[i] + "\n")
                if i == 0:
                    workers = "node" + str(i+1)
                else:
                    workers = workers + ",node" + str(i+1)
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "\nworker.loadbalancer.type=lb\n")
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.loadbalancer.balance_workers=" + workers + "\n")
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.loadbalancer.sticky_session=True\n")
            Utility.appendToFile(self.dirApacheInstall + "/conf/workers.properties", "worker.status.type=status")
        ###############################################################
        # mod_proxy
        ###############################################################
        elif self.options.loadbalancer == 'mod_proxy':
            balanceMembers = ""
            for i in range(int(self.options.jbossInstances)):
                nodeName = "node" + str(i+1)
                balanceMembers += "BalancerMember ajp://" + self.ipAddresses[i] + ":8009 route=" + nodeName + " loadfactor=1 ping=10 ttl=600\n"
            
            Utility.appendToFile(self.dirApacheInstall + "/conf/httpd.conf", """
\n
<Proxy balancer://mycluster>
""" + balanceMembers + """
</Proxy>

ProxyTimeout 120
ProxyStatus On

ProxyPass /jmx-console balancer://mycluster/jmx-console stickysession=JSESSIONID
ProxyPass /counter balancer://mycluster/counter stickysession=JSESSIONID
    """)
        ###############################################################
        # mod_cluster
        ###############################################################
        elif self.options.loadbalancer == 'mod_cluster':
            Utility.appendToFile(self.dirApacheInstall + "/conf/httpd.conf", "\n# Include mod_cluster configuration file\nInclude conf/mod-cluster.conf")
            
            #generate the mod-cluster.conf
            
            modClusterConf = """
LoadModule slotmem_module modules/mod_slotmem.so
LoadModule manager_module modules/mod_manager.so
LoadModule proxy_cluster_module modules/mod_proxy_cluster.so
LoadModule advertise_module modules/mod_advertise.so
        
Listen 127.0.0.1:6666
<VirtualHost 127.0.0.1:6666>
    <Directory />
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1
    </Directory>
    
    KeepAliveTimeout 60
    MaxKeepAliveRequests 0
    
    ManagerBalancerName mycluster
"""
            if self.options.modClusterAdvertise == "true":
                modClusterConf += """
    AdvertiseFrequency 5
"""
            else:
                modClusterConf += """
    ServerAdvertise off           
"""
            modClusterConf += """
</VirtualHost>

<Location /mod_cluster-manager>
    SetHandler mod_cluster-manager
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
</Location>
"""
            
            Utility.appendToFile(self.dirApacheInstall + "/conf/mod-cluster.conf", modClusterConf)
            
            #Enterprise_5.0.1.GA_rhel5_64
            
            modClusterKey = ""
            if self.options.jbossType == 'Enterprise':
                modClusterKey = self.options.jbossType + "_" + self.options.jbossVersion + "_" + self.options.architecture
            else:
                modClusterKey = self.options.jbossType + "_" + self.options.modClusterVersion + "_" + self.options.architecture
            modClusterFilename = self.modClusterSoVersions[modClusterKey].filename
             
            if "5." in self.options.jbossVersion:
                #Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/eap/500/mod-cluster_server.xml", self.dirSandboxTemp + "/mod-cluster_server.xml")
                #Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/eap/500/jboss-beans.xml", self.dirSandboxTemp + "/jboss-beans.xml")
                 
                for i in range(int(self.options.jbossInstances)):
                    nodeName = "node" + str(i+1)
                     
                    Utility.moveOnLinux(self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/server.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/server.xml.bak")
                    serverDotXml = """<Server>

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.jboss.web.tomcat.service.deployers.MicrocontainerIntegrationLifecycleListener" delegateBeanName="""

                    #Defaults to Enterprise version, I don't like the way this is handled
#                    if None == self.options.modClusterVersion:
#                        serverDotXml += '"ModClusterService" />'
#                    elif "1.0.3" in self.options.modClusterVersion or "1.0.4" in self.options.modClusterVersion:
#                        if int(self.options.jbossInstances) == 1:
#                            serverDotXml += '"ModClusterService" />'
#                        else:
#                            serverDotXml += '"HAModClusterService" />'
#                    elif "1.1.0" in self.options.modClusterVersion:
#                        serverDotXml += '"ModClusterListener" />'
                        
                    if None == self.options.modClusterVersion:
                        if int(self.options.jbossInstances) == 1:
                            serverDotXml += '"ModClusterService" />'    
                        else:
                            serverDotXml += '"HAModClusterService" />'
                    elif "1.1" in self.options.modClusterVersion:
                        serverDotXml += '"ModClusterListener" />'
                    elif int(self.options.jbossInstances) == 1:
                        serverDotXml += '"ModClusterService" />'    
                    else:
                        serverDotXml += '"HAModClusterService" />'
                        
                    serverDotXml += """

<Service name="jboss.web">

   <!-- A HTTP/1.1 Connector on port 8080 -->
   <Connector protocol="HTTP/1.1" port="8080" address="${jboss.bind.address}" connectionTimeout="20000" redirectPort="8443" maxThreads="200" />
   <Connector protocol="AJP/1.3" port="8009" address="${jboss.bind.address}" redirectPort="8443" maxThreads="8009" connectionTimeout="600000" />

   <Engine name="jboss.web" defaultHost="localhost" jvmRoute=""" + '"' + nodeName + '"' + """>

      <Realm className="org.jboss.web.tomcat.security.JBossWebRealm"
         certificatePrincipal="org.jboss.security.auth.certs.SubjectDNMapping"
         allRolesMode="authOnly"
         />

      <Host name="localhost"> 

         <Valve className="org.jboss.web.tomcat.service.jca.CachedConnectionValve"
             cachedConnectionManagerObjectName="jboss.jca:service=CachedConnectionManager"
             transactionManagerObjectName="jboss:service=TransactionManager" />
             
      </Host>
   </Engine>

</Service>

</Server>                            
"""
                    Utility.writeToFile(self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/server.xml", serverDotXml)
                      
                    Utility.moveOnLinux(self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/META-INF/jboss-beans.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/META-INF/jboss-beans.xml.bak")
                    jbossBeansDotXml = """<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="WebServer" class="org.jboss.web.tomcat.service.deployers.TomcatService">
   <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=WebServer", exposedInterface=org.jboss.web.tomcat.service.deployers.TomcatServiceMBean.class,registerDirectly=true)</annotation>
   <depends>jboss.jca:service=CachedConnectionManager</depends>
   <depends>jboss:service=TransactionManager</depends>
   <depends>""" 
                    #Defaults to Enterprise version, I don't like the way this is handled
#                    if None == self.options.modClusterVersion:
#                        jbossBeansDotXml += 'ModClusterService'
#                    elif "1.0.3" in self.options.modClusterVersion or "1.0.4" in self.options.modClusterVersion:
#                        if int(self.options.jbossInstances) == 1:
#                            jbossBeansDotXml += 'ModClusterService'
#                        else:
#                            jbossBeansDotXml += 'HAModClusterService'
#                    elif "1.1.0" in self.options.modClusterVersion:
#                        jbossBeansDotXml += '"ModClusterListener'
                        
                    if None == self.options.modClusterVersion:
                        if int(self.options.jbossInstances) == 1:
                            jbossBeansDotXml += 'ModClusterService'    
                        else:
                            jbossBeansDotXml += 'HAModClusterService'
                    elif "1.1" in self.options.modClusterVersion:
                        jbossBeansDotXml += 'ModClusterListener'
                    elif int(self.options.jbossInstances) == 1:
                        jbossBeansDotXml += 'ModClusterService'    
                    else:
                        jbossBeansDotXml += 'HAModClusterService'
                        
                        
                    jbossBeansDotXml += """</depends>

   <property name="tomcatDeployer"><inject bean="WarDeployer"/></property>
   <property name="securityManagerService">
      <inject bean="jboss.security:service=JaasSecurityManager" />
   </property>
</bean>
<bean name="WebServerMO"
   class="org.jboss.web.tomcat.service.management.WebServer">
   <property name="domain">jboss.web</property>
   <property name="nameProps">
      <map class="java.util.Properties" keyClass="java.lang.String" valueClass="java.lang.String">
         <entry>
            <key>service</key>
            <value>WebServer</value>
         </entry>
      </map>
   </property>
</bean>
<bean name="ConnectorBean-http-${jboss.bind.address}-8080MO"
   class="org.jboss.web.tomcat.service.management.ConnectorBean">
   <property name="domain">jboss.web</property>
   <property name="nameProps">
      <map class="java.util.Properties" keyClass="java.lang.String" valueClass="java.lang.String">
         <entry>
            <key>type</key>
            <value>GlobalRequestProcessor</value>
         </entry>
      </map>
   </property>
   <property name="port">
      <value-factory bean="ServiceBindingManager"
         method="getIntBinding" >
         <parameter>jboss.web:service=WebServer</parameter>
      </value-factory>
   </property>
   <property name="address">
      <value-factory bean="ServiceBindingManager"
         method="getStringBinding" >
         <parameter>jboss.web:service=WebServer</parameter>
      </value-factory>
   </property>
   <property name="server"><inject bean="JMXKernel" property="mbeanServer"/></property>
</bean>
<bean name="ThreadPool-http-${jboss.bind.address}-8080MO"
   class="org.jboss.web.tomcat.service.management.ThreadPool">
   <property name="domain">jboss.web</property>
   <property name="nameProps">
      <map class="java.util.Properties" keyClass="java.lang.String" valueClass="java.lang.String">
         <entry>
            <key>type</key>
            <value>ThreadPool</value>
         </entry>
      </map>
   </property>
   <property name="port">
      <value-factory bean="ServiceBindingManager"
         method="getIntBinding" parameter="jboss.web:service=WebServer"/>
   </property>
   <property name="address">
      <value-factory bean="ServiceBindingManager"
         method="getStringBinding" parameter="jboss.web:service=WebServer"/>
   </property>
   <property name="server"><inject bean="JMXKernel" property="mbeanServer"/></property>
</bean>
<bean name="${jboss.bind.address}-MO"
   class="org.jboss.web.tomcat.service.management.Host">
   <property name="domain">jboss.web</property>
   <property name="nameProps">
      <map class="java.util.Properties" keyClass="java.lang.String" valueClass="java.lang.String">
         <entry>
            <key>type</key>
            <value>Host</value>
         </entry>
      <entry>
         <key>host</key>
         <value>
            <value-factory bean="ServiceBindingManager"
               method="getStringBinding" parameter="jboss.web:service=WebServer"/>
         </value>
      </entry>
      </map>
   </property>
</bean>
</deployment>                          
"""
                    Utility.writeToFile(self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/META-INF/jboss-beans.xml", jbossBeansDotXml)
                         
            #Assumes mod_cluster 1.1
            elif "6." in self.options.jbossVersion:
                for i in range(int(self.options.jbossInstances)):
                    nodeName = "node" + str(i+1)
                     
                    Utility.moveOnLinux(self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/server.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/server.xml.bak")
                    serverDotXml = """<Server>

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.jboss.web.tomcat.service.deployers.MicrocontainerIntegrationLifecycleListener" delegateBeanName="ModClusterListener" />
<Service name="jboss.web">

   <!-- A HTTP/1.1 Connector on port 8080 -->
   <Connector protocol="HTTP/1.1" port="8080" address="${jboss.bind.address}" connectionTimeout="20000" redirectPort="8443" maxThreads="200" />
   <Connector protocol="AJP/1.3" port="8009" address="${jboss.bind.address}" maxThreads="200" connectionTimeout="600000" />

   <Engine name="jboss.web" defaultHost="localhost" jvmRoute=""" + '"' + nodeName + '"' + """>

      <Realm className="org.jboss.web.tomcat.security.JBossWebRealm"
         certificatePrincipal="org.jboss.security.auth.certs.SubjectDNMapping"
         allRolesMode="authOnly"
         />

      <Host name="localhost"> 

         <Valve className="org.jboss.web.tomcat.service.jca.CachedConnectionValve"
             cachedConnectionManagerObjectName="jboss.jca:service=CachedConnectionManager"
             transactionManagerObjectName="jboss:service=TransactionManager" />
             
      </Host>
   </Engine>

</Service>

</Server>                            
"""
                    Utility.writeToFile(self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/server.xml", serverDotXml)
                      
                    Utility.moveOnLinux(self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/META-INF/jboss-beans.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/META-INF/jboss-beans.xml.bak")
                    jbossBeansDotXml = """<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<bean name="WebServer" class="org.jboss.web.tomcat.service.deployers.TomcatService">
   <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.web:service=WebServer", exposedInterface=org.jboss.web.tomcat.service.deployers.TomcatServiceMBean.class,registerDirectly=true)</annotation>
   <property name="tomcatDeployer"><inject bean="WarDeployer"/></property>
   <property name="securityManagerService"><inject bean="jboss.security:service=JaasSecurityManager" /></property>
   <depends>jboss.jca:service=CachedConnectionManager</depends>
   <!-- Transaction manager for unfinished transaction checking in the CachedConnectionValve -->      
   <depends>jboss:service=TransactionManager</depends>
   <depends>ModClusterListener</depends>
</bean>
</deployment>"""
                    Utility.writeToFile(self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/META-INF/jboss-beans.xml", jbossBeansDotXml)
                     
            else:
                self.log.error("Please use mod_cluster with JBoss 5.x and greater")
                sys.exit(1)
            
            
            
            if "Enterprise" == self.options.jbossType:
                modClusterKey = self.options.jbossType + "_" + self.options.jbossVersion + "_" + self.options.architecture
                modClusterFilename = self.modClusterSoVersions[modClusterKey].filename
            
                #Downloading jboss-eap-native-5.0.1-RHEL5-x86_64.zip for example
                Utility.downloadEnterpriseProductIfNotInArchives(self.modClusterSoVersions[modClusterKey].filename, self.modClusterSoVersions[modClusterKey].url, self.dirArchives + "/mod_cluster")
                Utility.unzipFileIntoDirOnLinux(self.dirArchives + "/mod_cluster/" + modClusterFilename, self.dirSandboxTemp)
                #jboss-eap-native-5.0.0.0_mod-cluster-RHEL5-*.zip contains the *.so files
                #jboss-eap-native-5.0.0_mod-cluster-bin.zip contains the mod_cluster.sar file
                if "5.0.0" in self.options.jbossVersion:
                    Utility.downloadEnterpriseProductIfNotInArchives("jboss-eap-native-5.0.0_mod-cluster-bin.zip", "https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=1243", self.dirArchives + "/mod_cluster")
                    Utility.unzipFileIntoDirOnLinux(self.dirArchives + "/mod_cluster/jboss-eap-native-5.0.0_mod-cluster-bin.zip", self.dirSandboxTemp)
                    
                    for i in range(int(self.options.jbossInstances)):
                        nodeName = "node" + str(i+1)
                        os.system("cp -r " + self.dirSandboxTemp + "/" + self.modClusterSoVersions[modClusterKey].extractsAs + "/mod_cluster/mod-cluster.sar " + self.jbossHome + "/server/" + nodeName + "/deploy")
    
                    os.system("find " + self.dirSandboxTemp + "/" + self.modClusterSoVersions[modClusterKey].extractsAs  + " | grep so | xargs -I {} mv {} " + self.dirSandbox + "/apache/modules")
                    
                elif "5.0.1" in self.options.jbossVersion or "5.1" in self.options.jbossVersion:
                    #mod_cluster.sar is already included with the EAP 5.0.1 so just copy it to the appropriate directory
                    for i in range(int(self.options.jbossInstances)):
                        nodeName = "node" + str(i+1)
                        #jbossHome in the Enterprise referss to JBOSS_HOME/jboss-as so we need to go up one directory here
                        os.system("cp -r " + self.jbossHome + "/../mod_cluster/mod-cluster.sar " + self.jbossHome + "/server/" + nodeName + "/deploy")
                    
                    #Copy the *.so files
                    #find $MODCLUSTER_EXTRACT_DIR | grep so | xargs -I {} mv {} $DIR_SANDBOX/apache/modules
                    os.system("find " + self.dirSandboxTemp + "/" + self.modClusterSoVersions[modClusterKey].extractsAs  + " | grep so | xargs -I {} mv {} " + self.dirSandbox + "/apache/modules")
                
                    
                #Only way to see to tell if mod_cluster 1.0.x as the Enterprise mod_cluster doesn't actually say
                #if "5.0.0" in self.options.jbossVersion or "5.0.1" in self.options.jbossVersion:
                #    Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/eap/500/mod-cluster_server.xml", self.dirSandboxTemp + "/mod-cluster_server.xml")
                #    Utility.downloadOnLinuxToFile("http://people.redhat.com/smendenh/eap/500/jboss-beans.xml", self.dirSandboxTemp + "/jboss-beans.xml")
                #    #For each node configure the mod_cluster configuration 
                #    
                #    if int(self.options.jbossInstances) > 1:
                #        for i in range(int(self.options.jbossInstances)):
                #            nodeName = "node" + str(i+1)
                #            #Fix up the server.xml
                #            Utility.replaceStringInFile(self.dirSandboxTemp + "/mod-cluster_server.xml", self.dirSandboxTemp + "/mod-cluster_server.xml.1", 'jvmRoute=""', 'jvmRoute="' + nodeName + '"')
                #            Utility.replaceStringInFile(self.dirSandboxTemp + "/mod-cluster_server.xml.1", self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/server.xml", 'ModClusterService', 'HAModClusterService')
                #            #Fix up the META-INF/jboss-beans.xml
                #            Utility.replaceStringInFile(self.dirSandboxTemp + "/jboss-beans.xml", self.jbossHome + "/server/" + nodeName + "/deploy/jbossweb.sar/META-INF/jboss-beans.xml", 'ModClusterService', 'HAModClusterService')
                #    else:
                #        #Fix up the server.xml with just 1 instance
                #        Utility.replaceStringInFile(self.dirSandboxTemp + "/mod-cluster_server.xml", self.jbossHome + "/server/node1/deploy/jbossweb.sar/server.xml", 'jvmRoute=""', 'jvmRoute="node1"')
                #        #Just copy the META-INF/jboss-beans.xml since the default is 1 instance
                #        Utility.moveOnLinux(self.dirSandboxTemp + "/jboss-beans.xml", self.jbossHome + "/server/node1/deploy/jbossweb.sar/META-INF/jboss-beans.xml")
            elif "Community" == self.options.jbossType:
                                  
                modClusterSarKey = self.options.jbossType + "_" + self.options.modClusterVersion

                #Copy the modcluster.sar to the deploy dir, no need if using JBoss AS 6, it already includes the mod_cluster.sar file
                if "6." not in self.options.jbossVersion:
                    Utility.downloadIfNotInArchives(self.modClusterSarVersions[modClusterSarKey].filename, self.modClusterSarVersions[modClusterSarKey].url, self.dirArchives + "/mod_cluster")
                    Utility.extractTargzIntoDirOnLinux(self.dirArchives + "/mod_cluster/" + self.modClusterSarVersions[modClusterSarKey].filename, self.dirSandboxTemp)
                    for i in range(int(self.options.jbossInstances)):
                            nodeName = "node" + str(i+1)
                            command = "cp -r %s/mod-cluster.sar %s/server/%s/deploy" % (self.dirSandboxTemp, self.jbossHome, nodeName)
                            self.log.debug("Executing command: %s", command)
                            os.system(command)
#                            os.system("cp -r " + self.dirSandboxTemp + "/mod-cluster.sar " + self.jbossHome + "/server/" + nodeName + "/deploy")

                #Redo the key to include the architecture
                modClusterSoKey = self.options.jbossType + "_" + self.options.modClusterVersion + "_" + self.options.architecture

                if "1.0.3" in self.options.modClusterVersion:
                    #Extract the *.so files to Apache
                    Utility.downloadIfNotInArchives(self.modClusterSoVersions[modClusterSoKey].filename, self.modClusterSoVersions[modClusterSoKey].url, self.dirArchives + "/mod_cluster")
                    Utility.extractTargzIntoDirOnLinux(self.dirArchives + "/mod_cluster/" + self.modClusterSoVersions[modClusterSoKey].filename, self.dirSandboxTemp)
                    os.system("cp " + self.dirSandboxTemp + "/*.so " + self.dirApacheInstall + "/modules")
                    
                elif "1.1.0" in self.options.modClusterVersion or "1.0.4" in self.options.modClusterVersion:
                    #Extract the *.so files to Apache
                    Utility.downloadIfNotInArchives(self.modClusterSoVersions[modClusterSoKey].filename, self.modClusterSoVersions[modClusterSoKey].url, self.dirArchives + "/mod_cluster")
                    Utility.extractTargzIntoDirOnLinux(self.dirArchives + "/mod_cluster/" + self.modClusterSoVersions[modClusterSoKey].filename, self.dirSandboxTemp)
                    #os.system("cp " + self.dirSandboxTemp + "/*.so " + self.dirApacheInstall + "/modules")
                    for soFile in self.necessaryModClusterSoFilenames:
                        output = Utility.executeCmdAndReturnOutput("find " + self.dirSandboxTemp + " | grep " + soFile)
                        output = output.replace('\n', '')
                        #output = os.system("find " + self.dirSandboxTemp + " | grep " + soFile)
                        self.log.debug("Found soFile: " + str(output))
                        #soFilePath = self.dirSandboxTemp + "/" + output[1:]
                        #self.log.debug("Adjusted path to: " + soFilePath)
                        cpCmd = "cp " + str(output) + " " + self.dirApacheInstall + "/modules"
                        cpCmd = cpCmd.replace('\n', '')
                        self.log.debug("Copy so Command: " + cpCmd)
                        os.system(cpCmd)

    #################################################################################
    # start Apache
    ##################################################################################
    def startApache(self):
        Utility.prettyPrint("Starting Apache")
        output = Utility.executeCmdAndReturnOutput(self.dirSandbox + "/apache.sh start")
        self.log.debug("startApache output: %s", output) 
        return output
    
    #################################################################################
    # stop Apache
    ##################################################################################
    def stopApache(self):
        Utility.prettyPrint("Stopping Apache")
        return Utility.executeCmdAndReturnOutput(self.dirSandbox + "/apache.sh stop")

    #################################################################################
    # Open terminals to quickly start JBoss instances and Apache
    ##################################################################################
    def openTerminals(self):
        Utility.prettyPrint("Opening Terminals")
        
        if(Utility.doesBinaryExist("xterm", False, False) != True and Utility.doesBinaryExist("gnome-terminal", False, False) != True):
            self.log.warn("Can not spawn terminals to start JBoss as gnome-terminal and xterm were not on the system, please install one of these to enable this feature")
            return
            
        if(Utility.doesBinaryExist("xterm", False, False)):
            #xterm has a -hold command, might need to research that a bit more, took it out as it was farking things up
            os.system("xterm -e \"cd " + self.dirSandbox + " && /bin/bash\" &")
        else:
            os.system("gnome-terminal --working-directory=" + self.dirSandbox + " &")
        
        # self.options.startJBoss refers to the command-line param --start-jboss which defaults to true
        if self.options.startJBoss == "true":
            for i in range(int(self.options.jbossInstances)):
                nodeName = "node" + str(i+1)
                if(Utility.doesBinaryExist("gnome-terminal", False, False)):
                    if i == 0:
                        if(Utility.doesBinaryExist("xterm", False, False)):
                            os.system("xterm -geometry 120x50 -e \"cd " + self.dirSandbox + " && sh -c ./" + nodeName + "-start-jboss.sh\" &")
                        elif(Utility.doesBinaryExist("gnome-terminal", False, False)):
                            os.system("gnome-terminal --geometry 120x50 --working-directory=" + self.dirSandbox + " -x sh -c \"./" + nodeName + "-start-jboss.sh; echo Due to a bug in gnome-terminal terminal may close in 5 seconds; sleep 5\" &")
                    else:
                        start = time.time()
                        end = time.time()
                        elapsed = end - start
                        output = ""
                        while  elapsed < 120 and "Started in" not in output:
                            time.sleep(1)
                            end = time.time()
                            elapsed = end - start
                            output = Utility.executeCmdAndReturnOutput("grep \"Started in\" " + self.jbossHome + "/server/node1/log/server.log")
                            #print "elapsed: " + str(elapsed)
                            #print "output: " + output
                        if(Utility.doesBinaryExist("xterm", False, False)):
                            os.system("xterm -geometry 120x50 -e \"cd " + self.dirSandbox + " && sh -c ./" + nodeName + "-start-jboss.sh\" &")
                        elif(Utility.doesBinaryExist("gnome-terminal", False, False)):
                            os.system("gnome-terminal --geometry 120x50 --working-directory=" + self.dirSandbox + " -x sh -c \"./" + nodeName + "-start-jboss.sh; echo Due to a bug in gnome-terminal terminal may close in 5 seconds; sleep 5\" &")
    
    #################################################################################
    # Start JBoss programatically
    ##################################################################################
    def startJBossProgrammatically(self):
        Utility.prettyPrint("Starting JBoss programmatically")
        
        #Start all nodes and make sure the first node is started completely
        for i in range(int(self.options.jbossInstances)):
            nodeName = "node" + str(i+1)
            
            if i == 0:
                p = Popen(self.dirSandbox + "/" + nodeName + "-start-jboss.sh", shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
            else:
                start = time.time()
                end = time.time()
                elapsed = end - start
                output = ""
                while  elapsed < 120 and "Started in" not in output:
                    time.sleep(1)
                    end = time.time()
                    elapsed = end - start
                    output = Utility.executeCmdAndReturnOutput("grep \"Started in\" " + self.jbossHome + "/server/node1/log/server.log")
                    print "."
                self.log.info(output)
                p = Popen(self.dirSandbox + "/" + nodeName + "-start-jboss.sh", shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
                
        #Make sure all nodes are completely started
        for i in range(int(self.options.jbossInstances)):
            nodeName = "node" + str(i+1)
            
            start = time.time()
            end = time.time()
            elapsed = end - start
            output = ""
            while  elapsed < 120 and "Started in" not in output:
                time.sleep(1)
                end = time.time()
                elapsed = end - start
                output = Utility.executeCmdAndReturnOutput("grep \"Started in\" " + self.jbossHome + "/server/" + nodeName + "/log/server.log")
                print "."
            self.log.info(output)
                
    #################################################################################
    # Stop JBoss programatically
    ##################################################################################
    def stopJBossProgrammatically(self):
        Utility.prettyPrint("Stopping JBoss programmatically")
        for i in range(int(self.options.jbossInstances)):
            nodeName = "node" + str(i+1)
            
            self.log.info("Stopping JBoss " + nodeName)
            output = Utility.executeCmdAndReturnOutput(self.dirSandbox + "/" + nodeName + "-stop-jboss.sh")
            self.log.debug("shutdown.sh -> " + output)
        
class Utility:
    
    logging.basicConfig(level=logging.DEBUG)
    log = logging.getLogger(name="Utility")
    ##################################################################################
    # Utility functions
    ##################################################################################
    @staticmethod
    def getWebpageContent(url):
        return urllib.urlopen(url).read()

    
    @staticmethod
    def unzip_file_into_dir(file, dir):
        #os.mkdir(dir, 0777)
        if not os.path.isdir(dir):
            os.mkdir(dir, 0777)
        else:
            os.chmod(dir, 0777)
        zfobj = zipfile.ZipFile(file)
        for name in zfobj.namelist():
            if name.endswith('/'):
                if not os.path.exists(name):
                    os.mkdir(os.path.join(dir, name))
            else:
                outfile = open(os.path.join(dir, name), 'wb')
                outfile.write(zfobj.read(name))
                outfile.close()
         
    @staticmethod       
    def unzipFileIntoDirOnLinux(file, dir):
        Utility.log.info("unzipping %s to %s", file, dir)
        os.system("unzip -q " + file + " -d " + dir)
    
    @staticmethod
    def extractTargzIntoDirOnLinux(file, dir):
        Utility.log.info("untaring %s to %s", file, dir)
        os.system("tar -xzf " + file + " --directory=" + dir)
    
    @staticmethod
    def handleRemoveReadonly(func, path, exc):
        excvalue = exc[1]
        if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
            os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
            func(path)
        else:
            raise
    
    @staticmethod
    def download(url, toLocalFile):
        file = urllib2.urlopen(url)
        output = open(toLocalFile,'wb')
        output.write(file.read())
        output.close()
    
    @staticmethod
    def urlretrieve(urlfile, fpath):
        f = urllib2.urlopen(urlfile)
        g = ''
        while True:
            a = f.read(1024*10)
            if not a:
                break
            print 'Read another 10k'
            g += a
        file = open(fpath, "wb")
        file.write(g)
        file.close()
    
    @staticmethod
    def replaceStringInFile(inFile, toFile, stringToReplace, stringToReplaceWith):
        Utility.log.debug("Opening " + inFile + " and replacing " + stringToReplace + " with " + stringToReplaceWith + " and saving in " + toFile)
        f = open(inFile)
        o = open(toFile,"w")
        while 1:
            line = f.readline()
            if not line: break
            line = line.replace(stringToReplace,stringToReplaceWith)
            o.write(line)
        o.close()
    
    @staticmethod
    def appendToFile(file, text):
        f = open(file, 'a')
        f.write(text)
        f.close()
        
    @staticmethod
    def writeToFile(file, text):
        f = open(file, 'w')
        f.write(text)
        f.close()
      
    @staticmethod  
    def makeFileExecutable(file):
        os.chmod(file, 0755)
        
    @staticmethod
    def archiveLocation(dirArchives, file):
        return dirArchives + "/" + file
        
    @staticmethod
    def downloadOnLinuxToFile(url, toLocalFile):
        Utility.log.info("Downloading " + url)
        os.system("wget --progress=dot:mega -c -O " + toLocalFile + " " + url)
    
    @staticmethod
    def copyDirsOnLinux(fromLocation, toLocation):
        Utility.log.info("Copying from " + fromLocation + " to " + toLocation)
        os.system("cp -r " + fromLocation + " " + toLocation)
    
    @staticmethod
    def moveOnLinux(fromLocation, toLocation):
        Utility.log.info("moving from " + fromLocation + " to " + toLocation)
        os.system("mv " + fromLocation + " " + toLocation)
        
    #Check every 5 seconds or so
    @staticmethod
    def dlProgress(count, blockSize, totalSize):
        global progressBarCount
        percent = int(count*blockSize*100/totalSize)
        
        if ((percent % 2) == 0):
            if (progressBarCount % 400) == 0:
                sys.stdout.write("%2d%%" % percent)
            if (progressBarCount % 400) == 0:
                sys.stdout.write("\r")
            if (progressBarCount % 16) == 0:
                sys.stdout.write(".")
            sys.stdout.flush()
            progressBarCount += 1
    
    @staticmethod
    def executeCmdAndReturnOutput(cmd):
        p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
        output = p.stdout.read()
        return output
    
    @staticmethod
    def doesBinaryExist(binary, exitIfNotExists, warnIfNotExists):
        testStr = "no " + binary + " in"
        output = Utility.executeCmdAndReturnOutput("which " + binary)
        if testStr in output:
            print output
            if exitIfNotExists:
                sys.exit("Could not find " + binary + " on the system.  Please use your package manager to install it")
            elif warnIfNotExists:
                Utility.log.warn("Could not find %s on the system. Please use your package manager to install it", binary)
            return False
        return True

    @staticmethod
    def downloadIfNotInArchives(filename, fullUrl, dirArchives):
        Utility.log.debug("Checking if %s exists in the archives directory ", filename)
        if not os.path.isfile(dirArchives + "/" + filename):
            Utility.log.warn(dirArchives + "/" + filename + " was not found, downloading " + filename + " to " + dirArchives + " for archival")
            os.chdir(dirArchives)
            Utility.log.info("Downloading: " + fullUrl)
            Utility.downloadOnLinuxToFile(fullUrl,  Utility.archiveLocation(dirArchives, filename))
        else:
            Utility.log.info("%s found in archives", filename)

    @staticmethod            
    def downloadEnterpriseProductIfNotInArchives(filename, url, dirArchives):
        Utility.log.debug("Checking if %s exists in the archives directory ", filename)
        if not os.path.isfile(dirArchives + "/" + filename):
            #self.log.error("%s was not found, please manually download this version of the EAP from %s and copy to %s for archival", dirArchives + "/" + jbossVersions[jbossVersion].filename, jbossVersions[jbossVersion].url, dirArchives)
            #TODO make this more robust by checking if firefox exists, if not fall back to another browser, but this works for now
            Utility.log.warn(dirArchives + "/" + filename + " was not found, please manually download this version of the EAP from " + url + " and copy to " + dirArchives + " for archival")
            Utility.doesBinaryExist("firefox", True, True)
            os.system("firefox " + url)
            #os.system("gnome-terminal --working-directory=" + dirArchives + " &")
            sys.exit(1)
        else:
            Utility.log.info("%s found in archives", filename)
            
    @staticmethod
    def getJsessionidFromCurlHeaders(headers):
        for item in headers.split('\n'):
            if "JSESSIONID" in item:
                return Utility.getJsessionidEqualsFromSetCookie(item)
        return ""
            
    @staticmethod
    def getJsessionidEqualsFromSetCookie(setCookieLine):
        #ex. "Set-Cookie: JSESSIONID=MWvFikmJOxfbuH9Ms5ce+Q__.node1; Path=/counter"
        for item in setCookieLine.split(' '):
            if "JSESSIONID" in item:
                return item.split(';')[0]
         
    @staticmethod   
    def prettyPrint(text):
        print "################################################################################"
        print "# " + text
        print "################################################################################"
      
    @staticmethod  
    def secondsToStr(t):
        rediv = lambda ll,b : list(divmod(ll[0],b)) + ll[1:]
        return "%d:%02d:%02d.%03d" % tuple(reduce(rediv,[[t*1000,],
        1000,60,60]))


class JBossInformation:
    def __init__(self, version, filename, url, extractsAs, type):
        self.version = version
        self.filename = filename
        self.url = url
        self.extractsAs = extractsAs
        self.type = type
    
class ModClusterInformation:
    def __init__(self, filename, url, extractsAs):
        self.filename = filename
        self.url = url
        self.extractsAs = extractsAs
        self.type = type
        
##################################################################################
# main code
##################################################################################
if __name__ == '__main__':
    
    start = time.time()
    
    clusterConfig = ClusterConfig()
    clusterConfig.setupJBoss()
    clusterConfig.configureJBoss()
    clusterConfig.buildApache()
    clusterConfig.configureApache()
    clusterConfig.buildLoadbalancer()
    clusterConfig.configureLoadbalancer()
    clusterConfig.openTerminals()
    
    #Add a few instructions to start/stop JBoss and Apache
    clusterConfig.log.info("To start and stop JBoss see the sandbox directory and execute 'node1-start-jboss.sh' and 'node1-stop-jboss.sh' for example.")
    clusterConfig.log.info("To start and stop Apache see the sandbox directory and execute 'sudo ./apache.sh [start|stop|restart]")

    elapsed = (time.time() - start)
    Utility.prettyPrint("Elapsed time: " + Utility.secondsToStr(elapsed))


